home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
emerald
/
emrldsys.lha
/
Language
/
Compiler
/
allocRegs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-16
|
21KB
|
808 lines
/*
* @(#)allocRegs.c 1.6 4/11/88
*/
#include "assert.h"
#include "regdefs.h"
#include "datadesc.h"
#include "allocate.h"
#include "genutils.h"
#include "system.h"
#include "error.h"
#include "trace.h"
#include "option.h"
#include "emit.h"
#include "consts.h"
/*
* Register allocation.
*/
typedef struct {
Boolean isFree:8;
unsigned int okBrandMask:24;
Brand brand;
} RegisterInfo;
static void TS_UpdateAIP();
RegisterInfo registers[MAXTEMPORARY - MINTEMPORARY + 1];
initializeRegisters()
{
register int i;
int allBrands = 0xff;
int dataBrand = 1 << DataBrand;
int odpBrand = allBrands & ~(1 << DataBrand);
assert((TEMPORARYREGS & LINKAGEREGS) == 0);
assert((LINKAGEREGS & ALLOCATABLEREGS) == 0);
assert((TEMPORARYREGS & ALLOCATABLEREGS) == 0);
assert((TEMPORARYREGS | ALLOCATABLEREGS | LINKAGEREGS) == 0xffff);
assert(regs_scratch >= MINTEMPORARY);
assert(regs_arg1 >= MINTEMPORARY);
assert(regs_arg2 >= MINTEMPORARY);
assert(regs_arg3 >= MINTEMPORARY);
assert(regs_scratch <= MAXTEMPORARY);
assert(regs_arg1 <= MAXTEMPORARY);
assert(regs_arg2 <= MAXTEMPORARY);
assert(regs_arg3 <= MAXTEMPORARY);
assert(regs_pc >= MINLINKAGE);
assert(regs_sp >= MINLINKAGE);
assert(regs_l >= MINLINKAGE);
assert(regs_g >= MINLINKAGE);
assert(regs_b >= MINLINKAGE);
assert(regs_ssp >= MINLINKAGE);
assert(NALLOCATABLE == 6);
assert(regs_scratch == 0);
assert(regs_arg1 == regs_scratch + 1);
assert(regs_arg2 == regs_arg1 + 1);
assert(regs_arg3 == regs_arg2 + 1);
for (i = MINTEMPORARY; i <= MAXTEMPORARY ; i++) {
registers[i].isFree = TRUE;
#ifdef vax
registers[i].okBrandMask = allBrands;
#endif
#ifdef sun
registers[i].okBrandMask = i < 2 ? odpBrand : dataBrand;
#endif
}
}
char *dummyBrandName = "Invalid";
char *brandNames[] = {
"Data",
"ODP",
"Addr",
"Vector",
"Variable",
"Monitor",
"InvokeQueue",
"Unused"
};
void claimReg(r_number, number, brand)
int r_number, number;
Brand brand;
{
register int i;
TRACE3(tempreg, 3, "Claiming %d registers (starting with %s) for brand %s",
number, RN(r_number), brandNames[(int)brand]);
for (i = r_number; i < r_number + number; i++) {
if (!registers[i].isFree) {
TRACE2(tempreg, 3, "Claimed reg %s is allocated to brand %s", RN(i),
brandNames[(int)registers[i].brand]);
preemptReg(i, 1);
}
registers[i].isFree = FALSE;
registers[i].brand = (i == r_number ? brand : (Brand) -1);
}
}
/*
* allocate a temporary register. It must succeed. If there are none
* available, then preempt one. Try to leave the top depth elements on the
* variable stack alone.
*/
int forceAllocateReg(number, brand, depth)
int number;
Brand brand;
int depth;
{
int regNo, i, candidates;
register Variable *v;
assert(number == 1);
regNo = allocateReg(number, brand);
if (regNo >= 0) return(regNo);
again:
for (v = vStackTop - depth; v >= vStack && regNo < 0; v--) {
regNo = ddHasTempReg(v->data, brand);
if (regNo < 0) regNo = ddHasTempReg(v->abCon, brand);
}
if (regNo < 0 && depth > 0) {
depth = 0;
goto again;
}
if (regNo < 0) {
implementationBug("Out of temporary registers");
}
claimReg(regNo, 1, brand);
return(regNo);
}
int allocateReg(number, brand)
int number;
Brand brand;
{
register int i, j, ulimit, found = FALSE;
ulimit = MAXTEMPORARY;
ulimit -= (number - 1);
for (i = MINTEMPORARY; i <= ulimit && !found; i++) {
found = TRUE;
for (j = 0; j < number && found; j++) {
if (!registers[i+j].isFree) found = FALSE;
if ((registers[i+j].okBrandMask & (1 << brand)) == 0) found = FALSE;
}
if (found) break;
}
if (found) {
for (j = 0; j < number; j++) {
registers[i + j].isFree = FALSE;
registers[i + j].brand = (j == 0 ? brand : (Brand) -1);
}
TRACE3(tempreg, 2, "Wanted %d regs for brand %s, got %s", number,
brandNames[(int)brand], RN(i));
return(i);
} else {
TRACE2(tempreg, 2, "Wanted %d regs for brand %s, got none", number,
brandNames[(int)brand]);
return(-1);
}
}
void freeAllRegs()
{
register int i;
TRACE0(tempreg, 5, "Freeing all registers");
for (i = 0; i < MAXTEMPORARY; i++) {
if (! registers[i].isFree) {
TRACE1(tempreg, 0, "freeAllRegs: register %s is not free", RN(i));
Comment("freeAllRegs: register %s is not free", RN(i));
}
registers[i].isFree = TRUE;
}
}
void freeReg(r_number, number)
unsigned int r_number;
int number;
{
register int i;
for (i = r_number; i < r_number + number; i++) {
if (i < MINTEMPORARY || i > MAXTEMPORARY) {
TRACE1(tempreg, 1, "Freeing non-existant temp reg %d", i);
} else {
if (i == number - 1 && registers[i+1].isFree &&
registers[i+1].brand == (Brand) -1) {
TRACE1(tempreg, 1, "Freeing registers, %s got forgotten", RN(i+1));
}
if (registers[i].isFree) {
TRACE1(tempreg, 0, "Register %s is already free", RN(i));
Comment("Register %s is already free", RN(i));
} else {
TRACE2(tempreg, 3, "Freeing register %s, brand %s", RN(i),
brandNames[(int)registers[i].brand]);
registers[i].isFree = TRUE;
}
}
}
}
void preemptKernelRegisters()
{
preemptReg(regs_scratch, 4);
}
extern NodePtr theNode;
void displayTempRegs()
{
register int i;
for (i = MINTEMPORARY; i <= MAXTEMPORARY; i++) {
fprintf(stdout, "%s %s %s\n", RN(i),
registers[i].isFree ? "free" : "allocated",
brandNames[(int)registers[i].brand]);
}
}
extern void vDisplayStack();
ensureAllocated(r_number, number)
int r_number, number;
{
register int i;
for (i = r_number; i < r_number + number; i++) {
if (registers[i].isFree) {
Comment("Register %s is used but is not allocated", RN(i));
TRACE1(tempreg, 0, "Register %s is used but it is not allocated", RN(i));
IFTRACE(tempreg, 1) {
displayTempRegs();
vDisplayStack();
}
}
}
}
Boolean ddOwnsReg(d, r)
DD d;
int r;
{
if (d.kind != DD_Address) return(FALSE);
if (d.value.address.base == Register &&
d.value.address.offset == r) return(TRUE);
if (d.value.address.base == r) return(TRUE);
if (d.value.address.hasIndex &&
d.value.address.indexReg == r) return(TRUE);
return(FALSE);
}
extern Variable *vStackTop, vStack[];
void moveToTempStack(v)
Variable *v;
{
DD data, abCon;
if (v->data.kind == DD_Address) {
assert(!v->data.value.address.hasIndex);
}
data.kind = DD_Address;
data.value.address = nullAddress;
data.value.address.base = regs_l;
IFTRACE(tempreg, 1) {
trace(1, "Moving to temp stack");
displayDD(stdout, v->data , '\n');
displayDD(stdout, v->abCon, '\n');
}
if (v->abCon.kind == DD_AbCon) {
/* only do the data */
TRACE0(tempreg, 1, "Moving only the data");
data.kind = DD_Address;
data.value.address = nullAddress;
data.value.address.base = regs_l;
data.value.address.offset = TS_Allocate(4, abConToBrand(v->abCon));
emitMove(v->data, data, 'l');
freeDD(v->data);
v->data = data;
} else {
TRACE0(tempreg, 1, "Moving the data and abcon");
data.value.address.offset = TS_Allocate(8, VariableBrand);
abCon = nextAddress(data);
setDDAbstractType(abCon, getDDAbstractType(v->abCon));
ddGenerateAssign(data, abCon, v->data, v->abCon);
v->data = data;
v->abCon = abCon;
}
}
void preemptReg(r_number, number)
int number, r_number;
{
register int i;
Variable *v;
for (i = r_number; i < r_number + number; i++) {
if (! registers[i].isFree) {
IFTRACE(tempreg, 1) {
trace(1, "Preempting register %s", RN(r_number));
displayTempRegs();
vDisplayStack();
}
for (v = vStackTop; v >= &vStack[0]; v--) {
if (ddOwnsReg(v->data, i) || ddOwnsReg(v->abCon, i)) {
moveToTempStack(v);
break;
}
}
if (!registers[i].isFree) {
ErrorMessage(theNode, "preempt register botch, save the source file\n\
and show it to norm");
freeReg((unsigned) i, 1);
Comment("Preempt register botch %s", RN(i));
}
}
}
}
void eraseTempIndication(dp, reg)
DD *dp;
int reg;
{
DD d;
d = *dp;
assert(d.kind == DD_Address);
if (d.value.address.baseIsTemporary &&
d.value.address.base == Register &&
d.value.address.offset == reg) {
d.value.address.baseIsTemporary = FALSE;
} else if (d.value.address.hasIndex &&
d.value.address.indexIsTemporary &&
d.value.address.indexReg == reg) {
d.value.address.indexIsTemporary = FALSE;
}
*dp = d;
}
int ddHasTempReg(d, brand)
DD d;
Brand brand;
{
if (d.kind != DD_Address) return(-1);
if (d.value.address.baseIsTemporary) {
if (d.value.address.base == Register &&
(registers[d.value.address.offset].okBrandMask & (1 << brand)) != 0)
return(d.value.address.offset);
} else if (d.value.address.hasIndex &&
d.value.address.indexIsTemporary &&
(registers[d.value.address.indexReg].okBrandMask & (1 << brand)) != 0) {
return(d.value.address.indexReg);
}
return(-1);
}
Boolean maybeClaimReg(r_number, brand, v)
int r_number;
Brand brand;
Variable *v;
{
if (ddOwnsReg(v->data, r_number) || ddOwnsReg(v->abCon, r_number))
return(TRUE);
claimReg(r_number, 1, brand);
return(FALSE);
}
/*
* Move the data part of a variable to a register. If the register number
* is >= 0 then we insist on particular registers, otherwise any reg will do.
* Update the variable to reflect the new state.
*/
void moveDataToRegister(v, reg, brand)
Variable *v;
int reg;
Brand brand;
{
DD data, abcon;
int t;
if (reg < 0) {
assert(FALSE);
if ((t = ddHasTempReg(v->data, brand)) == -1) {
t = allocateReg(1, brand);
}
data = buildRegisterDD(t);
emitMove(v->data, data, 'l');
FREEDD(v->data);
claimReg(t, 1, brand);
v->data = data;
} else {
if (ddOwnsReg(v->data, reg)) {
data = buildRegisterDD(reg);
emitMove(v->data, data, 'l');
FREEDD(v->data);
claimReg(reg, 1, brand);
v->data = data;
} else {
claimReg(reg, 1, brand);
data = buildRegisterDD(reg);
emitMove(v->data, data, 'l');
FREEDD(v->data);
v->data = data;
}
}
if (v->abCon.kind == DD_Address &&
v->abCon.value.address.base == regs_sp &&
v->abCon.value.address.autoIncrement) {
emit(POPABCON);
}
abcon.kind = DD_AbCon;
setDDConcreteType(abcon,
(v->abCon.kind == DD_AbCon ? getDDConcreteType(v->abCon) : 0));
setDDAbstractType(abcon, getDDAbstractType(v->abCon));
FREEDD(v->abCon);
v->abCon = abcon;
}
/*
* Move a variable to a register. If the register number
* is >= 0 then we insist on particular registers, otherwise any regs will do.
* Update the variable to reflect the new state.
*/
void moveVariableToRegisters(v, reg)
Variable *v;
int reg;
{
DD data, abCon;
assert(reg >= 0);
if (ddOwnsReg(v->data, reg)) {
data = buildRegisterDD(reg);
emitMove(v->data, data, 'l');
FREEDD(v->data);
v->data = data;
if (ddOwnsReg(v->abCon, reg+1)) {
abCon = buildRegisterDD(reg+1);
emitMove(v->abCon, abCon, 'l');
FREEDD(v->abCon);
v->abCon = abCon;
claimReg(reg, 2, VariableBrand);
} else {
claimReg(reg, 2, VariableBrand);
abCon = buildRegisterDD(reg+1);
emitMove(v->abCon, abCon, 'l');
FREEDD(v->abCon);
v->abCon = abCon;
}
} else {
claimReg(reg, 2, VariableBrand);
data = buildRegisterDD(reg);
emitMove(v->data, data, 'l');
FREEDD(v->data);
v->data = data;
abCon = buildRegisterDD(reg+1);
emitMove(v->abCon, abCon, 'l');
FREEDD(v->abCon);
v->abCon = abCon;
}
}
int operationTempSize = 0, operationMaxStack = 0;
int obNumber, opNumber;
static AllocationInfoPtr theaip;
static int localSize = 0, registerOffset;
static int minimumOffset = 0;
static int globalOffset, localOffset, boringOffset;
typedef struct sTSChunk {
int offset;
int size;
Boolean isAllocated:1;
Boolean otherHalfAllocated:1;
unsigned int unused:14;
Brand brand:16;
struct sTSChunk *next;
} TSChunk, *TSChunkPtr;
static TSChunkPtr head = NULL;
typedef struct sTSI {
int saveStackSize;
struct sTSI *prev;
} TSI, *TSIPtr;
static TSIPtr stack = NULL;
static int stackSize = 0;
void TS_startOperation(aip, objectNumber, operationNumber)
AllocationInfoPtr aip;
int objectNumber, operationNumber;
{
int i, lRegisterOffset;
theaip = aip;
obNumber = objectNumber;
opNumber = operationNumber;
operationTempSize = 0;
operationMaxStack = 0;
localSize = 0;
wroteCode = TRUE;
TRACE2(tempstack, 3, "TS_startOperation op %d pass %d",
operationNumber, doGenerateCode);
if (theaip != NULL) {
localSize +=
theaip->boringSize + theaip->localSize + theaip->attachedLocalSize +
theaip->globalSize + theaip->attachedGlobalSize +
theaip->monitorSize + theaip->invokeQueueSize;
IFOPTION(allocateregisters, 1) {
registerOffset = localSize + sizeof(int);
for (i = 0; i < NALLOCATABLE; i++) {
if (theaip->regs[i].isAllocated) localSize += sizeof(int);
}
}
}
if (doGenerateCode) {
/* this is the second pass, and from aip we get what we need. */
boringOffset = firstLocalOffset + theaip->invokeQueueSize +
theaip->boringSize;
localOffset = boringOffset + aip->localSize + aip->attachedLocalSize;
globalOffset = localOffset + aip->globalSize + aip->attachedGlobalSize;
generateEnterOperation(
aip == NULL ? sizeof(InvokeQueue) : aip->operationTempSize + localSize,
aip == NULL ? sizeof(InvokeQueue) : aip->operationMaxStack);
if (OPTION(invokequeue, 2) && theaip->invokeQueueSize > 0) {
emit("\tinsque\t-%d(r%d),%d(r%d)\n",
firstLocalOffset+sizeof(InvokeQueue), regs_l, GOD_ARListHead, regs_b);
}
IFOPTION(allocateregisters, 1) {
if (theaip != NULL) {
lRegisterOffset = registerOffset;
for (i = 0; i < NALLOCATABLE; i++) {
if (theaip->regs[i].isAllocated) {
lRegisterOffset += sizeof(int);
}
}
i = 0;
while (i < NALLOCATABLE) {
if (theaip->regs[i].isAllocated &&
i < NALLOCATABLE - 1 && theaip->regs[i+1].isAllocated) {
ddGenerateAssign(
buildAddressDD(regs_l, -lRegisterOffset),
buildAddressDD(regs_l, -(lRegisterOffset - 4)),
buildRegisterDDNC(i+MINALLOCATABLE),
buildRegisterDDNC(i+1+MINALLOCATABLE));
IFOPTION(nilspace, 1) ddGenerateAssign(
buildRegisterDDNC(i+MINALLOCATABLE),
buildRegisterDDNC(i+MINALLOCATABLE+1),
nilDD,
nilDD);
lRegisterOffset -= 2 * sizeof(int);
i += 2;
} else if (theaip->regs[i].isAllocated) {
emitMove(buildRegisterDDNC(i+MINALLOCATABLE), buildAddressDD(regs_l, -lRegisterOffset), 'l');
IFOPTION(nilspace, 1) emitMove(nilDD, buildRegisterDDNC(i+MINALLOCATABLE), 'l');
lRegisterOffset -= sizeof(int);
i ++;
} else {
i ++;
}
}
}
}
}
minimumOffset = localSize + firstLocalOffset;
INITIALIZEJUMPDEBUG();
}
void TS_fixSPForHandler()
{
emitMoveAddress(
buildAddressDD(regs_l, -(theaip->operationTempSize + localSize + 4)),
buildRegisterDDNC(regs_sp),
'l');
}
extern void generateMonExit();
void TS_endOperation(monExit, initiallyDone, endRecovery)
Boolean monExit, initiallyDone, endRecovery;
{
TSChunkPtr p;
int lRegisterOffset, i;
wroteCode = TRUE;
TRACE2(tempstack, 3, "TS_endOperation op %d pass %d",
opNumber, doGenerateCode);
emit("L_operationreturn_%d:\n", opNumber);
if (monExit) generateMonExit();
emit("L_operationreturnnomonexit_%d:\n", opNumber);
if (initiallyDone) generateKernelCall("em_initiallyDone");
if (endRecovery) generateKernelCall("em_endRecovery");
IFOPTION(allocateregisters, 1) {
if (theaip != NULL) {
lRegisterOffset = registerOffset;
for (i = 0; i < NALLOCATABLE; i++) {
if (theaip->regs[i].isAllocated) {
lRegisterOffset += sizeof(int);
}
}
i = 0;
while (i < NALLOCATABLE) {
if (theaip->regs[i].isAllocated &&
i < NALLOCATABLE - 1 && theaip->regs[i+1].isAllocated) {
ddGenerateAssign(
buildRegisterDDNC(i+MINALLOCATABLE),
buildRegisterDDNC(i+1+MINALLOCATABLE),
buildAddressDD(regs_l, -lRegisterOffset),
buildAddressDD(regs_l, -(lRegisterOffset - 4)));
lRegisterOffset -= 2 * sizeof(int);
i += 2;
} else if (theaip->regs[i].isAllocated) {
emitMove(
buildAddressDD(regs_l, -lRegisterOffset),
buildRegisterDDNC(i+MINALLOCATABLE), 'l');
lRegisterOffset -= sizeof(int);
i ++;
} else {
i ++;
}
}
}
}
if (theaip == NULL) {
/* this is a process return. */
assert(operationTempSize == 0);
generateReturn(0);
} else {
generateReturn(theaip->parameterSize);
}
HSDump();
FINALIZEJUMPDEBUG();
if (theaip == NULL) {
/* do nothing */
} else {
operationMaxStack += localSize + operationTempSize;
TS_UpdateAIP();
}
emit("L_endoperation_%d:\n", opNumber);
#ifdef vax
emit("\t.byte\t0\n");
#endif
#ifdef sun
emit("\t.word\t0\n");
#endif
while (head != NULL) {
p = head;
head = head->next;
free((char *) p);
}
}
void TS_StartInvocation()
{
register TSIPtr t;
TRACE0(tempstack, 5, "TS_StartInvocation");
t = (TSIPtr) calloc(sizeof(TSI), 1);
t->saveStackSize = stackSize;
t->prev = stack;
stack = t;
}
void TS_Results(n)
int n;
{
TRACE1(tempstack, 5, "TS_Results: %d", n);
stackSize += n;
}
void TS_Push()
{
TRACE1(tempstack, 5, "TS_Push: %d", 8);
stackSize += 8;
}
void TS_EndInvocation()
{
register TSIPtr t = stack;
TRACE0(tempstack, 5, "TS_EndInvocation");
stackSize += 16 /* sizeof(DynamicLink) */;
if (stackSize > operationMaxStack) {
TRACE2(tempstack, 5, " maxstack changed from %d to %d", operationMaxStack,
stackSize);
operationMaxStack = stackSize;
}
stackSize = t->saveStackSize;
stack = t->prev;
free((char *) t);
}
int TS_Allocate(size, brand)
int size;
Brand brand;
{
Boolean found = FALSE;
TSChunkPtr runner, trailer, p;
TRACE2(tempstack, 1, "Temp stack %d bytes for brand %s", size,
brandNames[(int)brand]);
for (runner=head, trailer=NULL;runner != NULL;trailer=runner, runner=runner->next) {
if (! runner->isAllocated &&
! runner->otherHalfAllocated &&
runner->brand == brand) {
if (runner->size == size) {
runner->isAllocated = TRUE;
runner->otherHalfAllocated = (brand == VariableBrand);
assert(runner->brand == brand);
p = runner;
TRACE0(tempstack, 1, "Found free space to use");
found = TRUE;
break;
}
}
}
if (!found) {
p = (TSChunkPtr) malloc(sizeof(TSChunk));
p->brand = brand;
if (! doGenerateCode) {
p->offset = (trailer == NULL ? minimumOffset : trailer->offset);
p->offset += size;
} else {
switch (brand) {
case DataBrand:
p->offset = boringOffset;
boringOffset -= size;
break;
case ODPBrand:
p->offset = localOffset;
localOffset -= size;
break;
case VariableBrand:
p->offset = globalOffset;
globalOffset -= size;
break;
default:
assert(FALSE);
break;
}
}
p->size = size;
p->isAllocated = TRUE;
p->otherHalfAllocated = (brand == VariableBrand);
p->next = NULL;
if (trailer == NULL) head = p; else trailer->next = p;
operationTempSize = p->offset + - minimumOffset;
}
TRACE1(tempstack, 1, "Answer is %d", -p->offset);
return(-p->offset);
}
void TS_Free(offset)
int offset;
{
TSChunkPtr runner;
offset = -offset;
for (runner=head; runner != NULL; runner=runner->next) {
if (runner->offset == offset) {
assert(runner->isAllocated);
runner->isAllocated = FALSE;
TRACE3(tempstack, 1, "Freeing offset %d, size %d, brand %s", -offset,
runner->size, brandNames[(int)runner->brand]);
if (runner->brand == VariableBrand) {
if (runner->otherHalfAllocated) {
TRACE0(tempstack, 5, "Other half still allocated");
} else {
TRACE0(tempstack, 5, "Other half already free");
}
}
return;
} else if (runner->brand == VariableBrand && runner->offset == offset + 4) {
/* you have freed the other half of a variable */
assert(runner->otherHalfAllocated);
runner->otherHalfAllocated = FALSE;
TRACE3(tempstack, 1,"Freeing other half of offset %d, size %d, brand %s",
-offset, runner->size, brandNames[(int)runner->brand]);
return;
}
}
assert(FALSE);
}
static void TS_UpdateAIP()
{
TSChunkPtr runner;
if (! doGenerateCode) {
theaip->operationTempSize = 0;
theaip->operationMaxStack = operationMaxStack;
for (runner = head; runner != NULL; runner = runner->next) {
runner->isAllocated = FALSE;
TRACE2(tempstack, 1, "brand %s bumped by %d",
brandNames[(int)runner->brand], runner->size);
switch (runner->brand) {
case DataBrand:
theaip->boringSize += runner->size;
break;
case ODPBrand:
theaip->localSize += runner->size;
break;
case VariableBrand:
theaip->globalSize += runner->size;
break;
default:
assert(FALSE);
break;
}
}
}
}